#include "transient_backdrop.h"
#include "transient_decal.h"

#include "util/log.h"
#include "graphics/graphics_util.h"

#include "util/mmgr.h"
#include "util/common_macros.h"

using namespace backdrop;
using namespace script;

TransientBackdrop::TransientBackdrop()
{
}

TransientBackdrop::~TransientBackdrop()
{
	Clear();
}

void TransientBackdrop::SetBackgroundImg(const std::string& Sprite)
{
	if (m_BackgroundImg.Create(Sprite))
	{
		if (m_BackgroundImg.GetImage() && !m_BackgroundImg.GetSpriteInst())
		{
			int Width = GetGraphics()->GetScreenWidth();
			int Height = GetGraphics()->GetScreenHeight();
			int ImgWidth = m_BackgroundImg.GetImage()->GetWidth();
			int ImgHeight = m_BackgroundImg.GetImage()->GetHeight();

			m_BackgroundImg.m_UV1 = math::Vec2(0.0f, 0.0f);

			m_BackgroundImg.m_UV2.x = (ImgWidth > Width) ? (float(Width) / float(ImgWidth)) : 1.0f;
			m_BackgroundImg.m_UV2.y = (ImgHeight > Height) ? (float(Height) / float(ImgHeight)) : 1.0f;
		}

		m_BackgroundImg.Setup(math::Vec2(0.0f, 0.0f), math::Vec2(1.0f, 1.0f));
	}
}

TransientDecal* TransientBackdrop::AddDecal(const std::string& Sprite, const math::Vec2& Pos, const math::Vec2& Dir, int Layer)
{
	if (TransientDecal* pDecal = new TransientDecal(this))
	{
		pDecal->Create(Sprite, Pos, Dir);
		pDecal->SetLayer(Layer);

		AddDecal(pDecal);
		return pDecal;
	}

	return NULL;
}

void TransientBackdrop::AddDecal(TransientDecal* pDecal)
{
	for (unsigned int i = 0; i < m_Decals.size(); i++)
	{
		if (m_Decals[i]->GetLayer() > pDecal->GetLayer()) {
			m_Decals.insert(m_Decals.begin()+i, pDecal);
			return;
		}
	}

	m_Decals.push_back(pDecal);
}

TransientDecal* TransientBackdrop::GetDecal(const math::Vec2& Pos)
{
	for (int i = (int)(m_Decals.size() - 1); i >= 0; i--)
	{
		if (m_Decals[i]->GetIsVisible() && m_Decals[i]->HitTest(Pos))
			return m_Decals[i];
	}

	return NULL;
}

void TransientBackdrop::DropDecal(TransientDecal* pDecal, bool bDelete)
{
	for (unsigned int i = 0; i < m_Decals.size(); i++)
	{
		if (pDecal == m_Decals[i])
		{
			m_Decals.erase(m_Decals.begin()+i);
			if (bDelete)
				UTIL_SAFE_DELETE(pDecal);
		}
	}
}

void TransientBackdrop::Clear()
{
	for (unsigned int i = 0; i < m_Decals.size(); i++)
		UTIL_SAFE_DELETE(m_Decals[i]);

	m_Decals.clear();
	m_BackgroundImg.Invalidate();
}

void TransientBackdrop::Tick(float dt, bool UpdatePos)
{
	if (m_BackgroundImg.IsValid())
		m_BackgroundImg.Tick(dt);

	for (unsigned int i = 0; i < m_Decals.size(); i++)
		m_Decals[i]->Tick(dt, UpdatePos);
}

void TransientBackdrop::RenderBackground()
{
	if (m_BackgroundImg.IsValid())
		m_BackgroundImg.Render();
}

void TransientBackdrop::RenderDecals()
{
	bool bEnableSnap = GraphicsUtil::SnapToPixel;
	GraphicsUtil::SnapToPixel = false;

	for (unsigned int i = 0; i < m_Decals.size(); i++)
		m_Decals[i]->Render();

	GraphicsUtil::SnapToPixel = bEnableSnap;
}

void TransientBackdrop::Render()
{
	RenderBackground();
	RenderDecals();
}

void TransientBackdrop::ResetDecals()
{
	for (unsigned int i = 0; i < m_Decals.size(); i++)
		m_Decals[i]->ResetPos();
}

bool TransientBackdrop::Load(const std::string& File, bool bClear)
{
	if (bClear) Clear();
	m_Name = File;

	LuaPlus::LuaState* pScript = ScriptHelper::CreateLuaState();
	bool bRet = false;

	if (!ScriptHelper::DoFile(*pScript, File))
		_LOG(MSG_ERROR, "Unable to load transient backdrop from file " << File << "!");
	else
		bRet = LoadTable(pScript);

	LuaPlus::LuaState::Destroy(pScript);
	return bRet;
}

bool TransientBackdrop::Save(const std::string& File)
{
	WriteLua Output;

	if (!Output.Open(File)) return false;
	m_Name = File;

	SaveTable(Output);
	return true;
}

bool TransientBackdrop::LoadTable(LuaPlus::LuaState* pScript)
{
	LuaPlus::LuaObject Decals = ScriptHelper::GetObj(*pScript, "Transient");
	bool bRet = false;

	if (bRet = Decals.IsTable())
	{
		int TableC = Decals.GetTableCount();
		for (int i = 0; i < TableC; i++)
		{
			LuaPlus::LuaObject Data = Decals.GetByIndex(i+1);
			std::string Image		= ScriptHelper::GetTableString(Data, "Image");

			if (!Image.empty()) {
				math::Vec2 Pos		= ScriptHelper::GetTableVec2(Data, "Pos");
				math::Vec2 Dir		= ScriptHelper::GetTableVec2(Data, "Dir");
				int Layer			= ScriptHelper::GetTableInt(Data, "Layer");
				//float Rotate		= ScriptHelper::GetTableFloat(Data, "Rotation");
				//math::Vec2 Cycle	= ScriptHelper::GetTableVec2(Data, "Cycle");

				AddDecal(Image, Pos, Dir, Layer);
			}
		}
	}

	LuaPlus::LuaObject Background = ScriptHelper::GetObj(*pScript, "Transient_Background");
	if (Background.IsTable())
	{
		std::string Image			= ScriptHelper::GetTableString(Background, "Image");

		if (!Image.empty())
			SetBackgroundImg(Image);
	}

	return bRet;
}

void TransientBackdrop::SaveTable(script::WriteLua& Output)
{
	if (m_Decals.size() > 0)
	{
		Output.StartTable("Transient");
		for (unsigned int i = 0; i < m_Decals.size(); i++)
		{
			Output.StartTable();
			Output.WritePair("Image",		m_Decals[i]->GetName());
			Output.WritePair("Pos",			m_Decals[i]->GetStartPos());
			Output.WritePair("Dir",			m_Decals[i]->GetDir());
			Output.WritePair("Layer",		m_Decals[i]->GetLayer());
			//Output.WritePair("Rotation",	m_Decals[i]->GetRotate());
			//Output.WritePair("Cycle",		m_Decals[i]->GetCycle());
			Output.CloseTable();
		}
		Output.CloseTable(false);
	}

	if (m_BackgroundImg.IsValid())
	{
		Output.StartTable("Transient_Background");
		Output.WritePair("Image",			m_BackgroundImg.GetFilename());
		Output.CloseTable(false);
	}
}
